package com.jiyici.model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

import jiyici.Constant.ItemParamType;
import jiyici.Constant.ModelColumn;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.util.Log;

import com.jiyici.utils.LogUtil;
import com.jiyici.utils.StringUtils;

public class ModelUtil {
    
    private static final String TAG = "model-util";
    
    public static String getRecordItemValue(Record record, ItemParam itemParam) {
        String value = "";
        int size = record.paramList.size();
        for (int j = 0; j < size; j++) {
            RecordParam rp = record.paramList.get(j);
            if (rp.itemParamId == itemParam.getId()) {
                value = rp.value;
                break;
            }
        }
        return value;
    }
    
    public static RecordParam getRecordItem(Record record, ItemParam itemParam) {
        RecordParam value = null;
        int size = record.paramList.size();
        for (int j = 0; j < size; j++) {
            RecordParam rp = record.paramList.get(j);
            if (rp.itemParamId == itemParam.getId()) {
                value = rp;
                break;
            }
        }
        return value;
    }
    
    public static ClientBaseModel createModel(String clazzName) {
        if (Category.class.getSimpleName().equals(clazzName))
            return new Category();
        else if (Item.class.getSimpleName().equals(clazzName))
            return new Item();
        else if (ItemParam.class.getSimpleName().equals(clazzName))
            return new ItemParam();
        else if (Record.class.getSimpleName().equals(clazzName)) {
            return new Record();
        } else if (RecordParam.class.getSimpleName().equals(clazzName)) {
            return new RecordParam();
        }
        LogUtil.error(TAG, "createModel not define for class: " + clazzName, null);
        return null;
    }
    
    public static final int SORT_ASC = 1;
    public static final int SORT_DESC = 2;
    
    public static void sordRecord(ArrayList<Record> recordList, ItemParam sortParam, int sort) {
        Collections.sort(recordList, new RecordComparator(sortParam == null, sortParam, sort));
    }
    
    private static class RecordComparator implements java.util.Comparator<Record> {
        
        private boolean isCompareDate;
        private ItemParam compareItemParam;
        private int sort;

        public RecordComparator(boolean isCompareDate, ItemParam compareItemParam, int sort) {
            super();
            this.isCompareDate = isCompareDate;
            this.compareItemParam = compareItemParam;
            this.sort = sort;
        }

        @Override
        public int compare(Record lhs, Record rhs) {
            return SORT_ASC == sort ? compareASC(lhs, rhs) : -compareASC(lhs, rhs);
        }
        
        private int compareASC(Record lhs, Record rhs) {
            if (isCompareDate) {
                return (lhs.recordTime >= rhs.recordTime) ? 1 : -1;
            }
            RecordParam lhsParam = getRecordParam(lhs, compareItemParam);
            RecordParam rhsParam = getRecordParam(rhs, compareItemParam);
            if (lhsParam == rhsParam) /* null, null case */
                return 0;
            if (lhsParam == null)
                return -1;
            if (rhsParam == null)
                return 1;
            String lhsValue = StringUtils.trimToEmpty(lhsParam.value);
            String rhsValue = StringUtils.trimToEmpty(rhsParam.value);
            if (lhsValue.equals(rhsValue))
                return 0;
            if (compareItemParam.paramType == ItemParamType.TEXT) {
                return lhsValue.compareTo(rhsValue);
            } else if (compareItemParam.paramType == ItemParamType.NUMBER) {
                double lhsNumberValue = 0;
                double rhsNumberValue = 0;
                try {
                    rhsNumberValue = Double.parseDouble(rhsValue);
                } catch (Exception e) {
                    return 1;
                }
                try {
                    lhsNumberValue = Double.parseDouble(lhsValue);
                } catch (Exception e) {
                    return -1;
                }
                return lhsNumberValue >= rhsNumberValue ? 1 : -1;
            }
            return 0;
        }
        
        private RecordParam getRecordParam(Record record, ItemParam itemParam) {
            ArrayList<RecordParam> params = record.paramList;
            if (params == null)
                return null;
            int size = params.size();
            for (int i = 0; i < size; i++) {
                RecordParam param = params.get(i);
                if (param.itemParamId == itemParam.getId())
                    return param;
            }
            return null;
        }
        
    }

    public static User json2User(JSONObject json) {
        try {
            User user = new User();
            user.id = json.getLong(ModelColumn.USER_COLUMN_ID);
            user.email = json.getString(ModelColumn.USER_COLUMN_EMAIL);
            user.userName = json.getString(ModelColumn.USER_COLUMN_USERNAME);
            user.token = json.getString(ModelColumn.USER_COLUMN_TOKEN);
            return user;
        } catch (JSONException e) {
            e.printStackTrace();
            return null;
        }
    }
    
    public static ArrayList<Item> json2ItemList(JSONObject json) {
        ArrayList<Item> itemList = new ArrayList<Item>();
        try {
            JSONArray jsonArray = json.getJSONArray("items");
            int size = jsonArray.length();
            for (int i = 0; i < size; i++) {
                JSONObject itemObject = jsonArray.getJSONObject(i);
                Item item = json2Item(itemObject);
                if (item != null) {
                    itemList.add(item);
                } else {
                    Log.e("", "[item] json data error");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return itemList;
    }
    
    public static Item json2Item(JSONObject json) {
        try {
            Item item = new Item();
            item.id = json.getLong(ModelColumn.BASE_COLUMN_ID);
            item.lastmodified = json.getLong(ModelColumn.BASE_COLUMN_LASTMODIFIED);
            item.deleted = json.getBoolean(ModelColumn.BASE_COLUMN_DELETED);
            item.itemName = json.getString(ModelColumn.ITEM_COLUMN_NAME);
            item.categoryId = json.getLong(ModelColumn.ITEM_COLUMN_CATEGORYID);
            item.displayIndex = json.getString(ModelColumn.ITEM_COLUMN_DISPLAY_INDEX);
            item.recordCount = json.getInt(ModelColumn.ITEM_COLUMN_RECORD_COUNT);
            item.params = new ArrayList<ItemParam>();
            JSONArray paramArray = json.getJSONArray(ModelColumn.ITEM_COLUMN_PARAMS);
            int size = paramArray.length();
            for (int i = 0; i < size; i++) {
                ItemParam param = json2ItemParam(paramArray.getJSONObject(i));
                if (param != null) {
                    item.params.add(param);
                } else {
                    Log.e("", "[item param] json data error");
                }
            }
            return item;
        } catch (JSONException e) {
            e.printStackTrace();
            return null;
        }
    }
    
    private static ItemParam json2ItemParam(JSONObject json) {
        try {
            ItemParam param = new ItemParam();
            param.id = json.getLong(ModelColumn.BASE_COLUMN_ID);
            param.lastmodified = json.getLong(ModelColumn.BASE_COLUMN_LASTMODIFIED);
            param.deleted = json.getBoolean(ModelColumn.BASE_COLUMN_DELETED);
            param.itemParamName = json.getString(ModelColumn.ITEM_PARAM_COLUMN_NAME);
            param.paramType = json.getInt(ModelColumn.ITEM_PARAM_COLUMN_TYPE);
            param.isMust = json.getBoolean(ModelColumn.ITEM_PARAM_COLUMN_IS_MUST);
            param.displayOrder = json.getString(ModelColumn.ITEM_PARAM_COLUMN_DISPLAY_ORDER);
            return param;
        } catch (JSONException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static JSONObject jsonOf(Item item) {
        JSONObject node = new JSONObject();
        try {
            node.put(ModelColumn.BASE_COLUMN_ID, item.id);
            node.put(ModelColumn.BASE_COLUMN_LASTMODIFIED, item.lastmodified);
            node.put(ModelColumn.BASE_COLUMN_DELETED, item.deleted);
            
            node.put(ModelColumn.ITEM_COLUMN_NAME, item.itemName);
            node.put(ModelColumn.ITEM_COLUMN_CATEGORYID, item.categoryId);
            node.put(ModelColumn.ITEM_COLUMN_DISPLAY_INDEX, item.displayIndex);
            node.put(ModelColumn.ITEM_COLUMN_RECORD_COUNT, item.recordCount);
            JSONArray arrayNode = new JSONArray();
            for (Iterator<ItemParam> i = item.params.iterator(); i.hasNext();) {
                ItemParam param = i.next();
                arrayNode.put(jsonOf(param));
            }
            node.put(ModelColumn.ITEM_COLUMN_PARAMS, arrayNode);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return node;
    }

    public static JSONObject jsonOf(ItemParam itemParam) {
        JSONObject node = new JSONObject();
        try {
            node.put(ModelColumn.BASE_COLUMN_ID, itemParam.id);
            node.put(ModelColumn.BASE_COLUMN_LASTMODIFIED, itemParam.lastmodified);
            node.put(ModelColumn.BASE_COLUMN_DELETED, itemParam.deleted);
            
            node.put(ModelColumn.ITEM_PARAM_COLUMN_NAME, itemParam.itemParamName);
            node.put(ModelColumn.ITEM_PARAM_COLUMN_TYPE, itemParam.paramType);
            node.put(ModelColumn.ITEM_PARAM_COLUMN_IS_MUST, itemParam.isMust);
            node.put(ModelColumn.ITEM_PARAM_COLUMN_DISPLAY_ORDER, itemParam.displayOrder);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return node;
    }
    
    public static ArrayList<Category> json2CategoryList(JSONObject json) {
        ArrayList<Category> categories = new ArrayList<Category>();
        try {
            JSONArray jsonArray = json.getJSONArray("categories");
            int size = jsonArray.length();
            for (int i = 0; i < size; i++) {
                JSONObject object = jsonArray.getJSONObject(i);
                Category category = json2Category(object);
                if (category != null) {
                    categories.add(category);
                } else {
                    Log.e("", "[category] json data error");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return categories;
    }
    
    public static Category json2Category(JSONObject json) {
        try {
            Category category = new Category();
            category.id = json.getLong(ModelColumn.BASE_COLUMN_ID);
            category.lastmodified = json.getLong(ModelColumn.BASE_COLUMN_LASTMODIFIED);
            category.deleted = json.getBoolean(ModelColumn.BASE_COLUMN_DELETED);
            category.name = json.getString(ModelColumn.CATEGORY_COLUMN_NAME);
            category.displayOrder = json.getString(ModelColumn.CATEGORY_COLUMN_DISPLAY_ORDER);
            return category;
        } catch (JSONException e) {
            e.printStackTrace();
            return null;
        }
    }
}
